/****************************************************************************
*                                                                           *
* Copyright (c) 2008 Nuvoton Electronics Corp. All rights reserved.         *
*                                                                           *
*****************************************************************************/

/****************************************************************************
* FILENAME
*   pwm_demo.c
*
* VERSION
*   1.0
*
* DESCRIPTION
*   The PWM test program of Nuvoton NUC900 MCU
*
* DATA STRUCTURES
*   None
*
* FUNCTIONS
*   PWM_Item
*   PWM_Timer
*   PWM_TimerDZ
*
* HISTORY
*   2007-11-23    Ver 1.0 Created
*
* REMARK
*   None
****************************************************************************/

#ifdef ECOS 
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "kapi.h"
#include "diag.h"
#include "wbio.h"
#else
#include "wblib.h"
#endif

#include "NUC900_pwm.h"

#ifdef ECOS
#define MSG		diag_printf
#define GETCH	diag_getc
#else
#define MSG		sysprintf
#define GETCH	sysGetChar
#endif

#ifdef ECOS
static cyg_handle_t  	thread_handle;
static cyg_thread 		thread;
#define STACKSIZE		(128*1024)
#define Successful		0
#define Fail			-1
static UINT8            _Statck[STACKSIZE];
#endif


VOID PWM_Item(VOID);
INT PWM_Timer(INT timer_num);
INT PWM_TimerDZ(INT dz_num);
#ifdef ECOS
VOID PWM_Sample (cyg_addrword_t tdata);
#else
VOID PWM_Sample (VOID);
#endif


int main (VOID)
{
	//int i;
	
#ifdef ECOS
	cyg_thread_create(22, PWM_Sample, 0, "pwm_smpl", _Statck, STACKSIZE, &thread_handle, &thread);
	cyg_thread_resume(thread_handle);
#else
	PWM_Sample();

#endif	
	
	return 0;
}


#ifdef ECOS
void PWM_Sample (cyg_addrword_t tdata)
#else
void PWM_Sample (VOID)
#endif
{
	INT item;
	do
	{
		PWM_Item();// Show menu
		item = GETCH();// Get user key
		switch(item)
		{
			case '0':	PWM_Timer(PWM_TIMER0);		break;
			case '1':	PWM_Timer(PWM_TIMER1);		break;
			case '2':	PWM_Timer(PWM_TIMER2);		break;
			case '3':	PWM_Timer(PWM_TIMER3);		break;
			case '4':	PWM_TimerDZ(PWM_TIMER0);	break;
			case '5':	PWM_TimerDZ(PWM_TIMER2);	break;
			default:				                break;
		}
	}while (item != 27);//do until user press ESC
}

VOID PWM_Item(VOID)
{
	MSG("\n\n\n");
	MSG("+------------------------------------------------------+\n");
	MSG("| Nuvoton PWM Diagnostic Code                          |\n");
	MSG("+------------------------------------------------------+\n");
	MSG("| PWM Timer0 test                                - [0] |\n");
	MSG("| PWM Timer1 test                                - [1] |\n");
	MSG("| PWM Timer2 test                                - [2] |\n");
	MSG("| PWM Timer3 test                                - [3] |\n");
	MSG("| PWM Dead zone 0 test                           - [4] |\n");
	MSG("| PWM Dead zone 1 test                           - [5] |\n");
	MSG("+------------------------------------------------------+\n");
	MSG("| Quit                                         - [ESC] |\n");
	MSG("+------------------------------------------------------+\n");
	MSG("Please Select : \r\n");
}

INT PWM_Timer(INT timer_num)
{
    typeTIMERVALUE timervalue;
    typePWMSTATUS PWMSTATUS;
    INT nLoop=0;
    INT nStatus=0;
    INT nInterruptInterval=0;
    PWMSTATUS.PDR=0;
    PWMSTATUS.InterruptFlag=FALSE;

    pwmInit();
    pwmOpen(timer_num);

    // Change PWM Timer setting
    pwmIoctl(timer_num, SET_CSR, 0, CSRD16);
    pwmIoctl(timer_num, SET_CP, 0, 249);
    pwmIoctl(timer_num, SET_DZI, 0, 0);
    pwmIoctl(timer_num, SET_INVERTER, 0, PWM_INVOFF);
    pwmIoctl(timer_num, SET_MODE, 0, PWM_ONESHOT);
    pwmIoctl(timer_num, DISABLE_DZ_GENERATOR, 0, 0);
    pwmIoctl(timer_num, ENABLE_PWMGPIOOUTPUT, 0, 0);

    timervalue.field.cnr=59999;
    timervalue.field.cmr=4999;
    pwmWrite(timer_num, (PUCHAR)(&timervalue), sizeof(timervalue));

    MSG("PWM Timer%d one shot mode test\nPWM. Timer interrupt will occure soon.", timer_num);

    //Start PWM Timer
    pwmIoctl(timer_num, START_PWMTIMER, 0, 0);

    while(1)
    {
        nLoop++;
        if(nLoop%100000 == 0)
        {
            MSG(".");
        }
        nStatus=pwmRead(timer_num, (PUCHAR)&PWMSTATUS, sizeof(PWMSTATUS));
        if(nStatus != Successful)
        {
            MSG("PWM read error, ERR CODE:%d",nStatus);
            pwmClose(timer_num);
            return Fail;
        }
        if(PWMSTATUS.InterruptFlag==TRUE)
        {
            MSG("\n\nPWM Timer interrupt occurred!\n\n");
            break;
        }
    }

     // Change PWM Timer setting
    pwmIoctl(timer_num, SET_CSR, 0, CSRD16);
    pwmIoctl(timer_num, SET_CP, 0, 255);
    pwmIoctl(timer_num, SET_DZI, 0, 0);
    pwmIoctl(timer_num, SET_INVERTER, 0, PWM_INVOFF);
    pwmIoctl(timer_num, SET_MODE, 0, PWM_TOGGLE);
    pwmIoctl(timer_num, DISABLE_DZ_GENERATOR, 0, 0);
    pwmIoctl(timer_num, ENABLE_PWMGPIOOUTPUT, 0, 0);


    nInterruptInterval=30000;
    timervalue.field.cnr=nInterruptInterval;
    timervalue.field.cmr=4999;
    pwmWrite(timer_num, (PUCHAR)(&timervalue), sizeof(timervalue));

    MSG("PWM Timer%d toggle mode test\nPWM Timer interrupt interval will decrease gradually\n", timer_num);

    //Start PWM Timer
    pwmIoctl(timer_num, START_PWMTIMER, 0, 0);
    nLoop=0;
    while(1)
    {
        nStatus=pwmRead(timer_num, (PUCHAR)&PWMSTATUS, sizeof(PWMSTATUS));
        if(nStatus != Successful)
        {
            MSG("PWM read error, ERR CODE:%d",nStatus);
            pwmClose(timer_num);
            return Fail;
        }
        if(PWMSTATUS.InterruptFlag==TRUE)
        {
            MSG("PWM Timer interrupt [%d], CNR:%d\n",nLoop,nInterruptInterval);
            nInterruptInterval/=2;
            timervalue.field.cnr=nInterruptInterval;
            timervalue.field.cmr=4999;
            pwmWrite(timer_num, (PUCHAR)(&timervalue), sizeof(timervalue));
            nLoop++;
            if(nLoop==10)
            {
                break;
            }
        }
    }
    pwmIoctl(timer_num, STOP_PWMTIMER, 0, 0);
    pwmClose(timer_num);
    MSG("\nPWM Timer %d test finish\nPress any key to continue....", timer_num);
    GETCH();
    return Successful;
}

INT PWM_TimerDZ(INT timer_num)
{
    typePWMSTATUS PWMSTATUS0;
    typePWMSTATUS PWMSTATUS1;
    INT nLoop=0;
    INT nStatus0=0,nStatus1=0;

    PWMSTATUS0.PDR=0;
    PWMSTATUS0.InterruptFlag=FALSE;
    PWMSTATUS1.PDR=0;
    PWMSTATUS1.InterruptFlag=FALSE;

    pwmInit();
    pwmOpen(timer_num);
    pwmOpen(timer_num+1);
    pwmIoctl(timer_num, ENABLE_PWMGPIOOUTPUT, 0, 0);

    pwmIoctl(timer_num, SET_DZI, 0, 0x50);
    pwmIoctl(timer_num, ENABLE_DZ_GENERATOR, 0, 0);

    pwmIoctl(timer_num, START_PWMTIMER, 0, 0);
    pwmIoctl(timer_num+1, START_PWMTIMER, 0, 0);
    nLoop=0;
    while(1)
    {
        nStatus0=pwmRead(timer_num, (PUCHAR)&PWMSTATUS0, sizeof(PWMSTATUS0));
        nStatus1=pwmRead(timer_num+1, (PUCHAR)&PWMSTATUS1, sizeof(PWMSTATUS1));
        if(nStatus0 != Successful || nStatus1 != Successful)
        {
            MSG("PWM read error, ERR CODE:%d %d",nStatus0,nStatus1);
            pwmClose(timer_num);
            pwmClose(timer_num+1);
            return Fail;
        }
        if(PWMSTATUS0.InterruptFlag==TRUE && PWMSTATUS1.InterruptFlag==TRUE)
        {
            nLoop++;
            if(nLoop==10)
            {
                break;
            }
        }
    }
    pwmIoctl(timer_num, STOP_PWMTIMER, 0, 0);
    pwmIoctl(timer_num+1, STOP_PWMTIMER, 0, 0);
    pwmClose(timer_num);
    pwmClose(timer_num+1);
    MSG("PWM Dead zone test finish\nPress any key to continue....");
    GETCH();
    return Successful;
}
